package dxn.nl.export.deal.export;

import dxn.boot.common.config.CsApplicationContext;
import dxn.nl.file.biz.ExportStatusEnum;
import dxn.nl.file.biz.manager.MinIoImageManager;
import dxn.nl.file.biz.po.FileExportApplyDetail;
import dxn.nl.file.biz.service.ExportFileBaseService;
import dxn.nl.file.client.model.dto.CsExportExcelSheetHeadDto;
import dxn.nl.file.client.model.dto.TransferMessageDto;
import dxn.nl.file.client.model.enums.ExportDealResultTypeEnum;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

public class ExportDealBaseBiz implements DisposableBean
{
    private static final AtomicInteger atomicInteger = new AtomicInteger(0);
    private static final Logger log = LoggerFactory.getLogger(ExportDealBaseBiz.class);
    private final List<String> filePathList = new ArrayList<>();
    protected final ExportFileBaseService exportFileBaseService;
    protected final FileExportApplyDetail fileExportApplyDetail;

    private final ExportExcelWriterBiz exportExcelWriterBiz;

    private int emptyDataTime = 0;
    private int totalRows = 0;
    private final int totalMaxCount = 600000;
    protected StringBuilder failMessages = new StringBuilder();
    protected DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private final String bucketName = "ims-export";

    /** 需要导出的文件名List **/
    private final List<String> remoteFileNames = new ArrayList<>();

    private final MinIoImageManager minIoImageManager;

    public ExportDealBaseBiz(HashMap<String, CsExportExcelSheetHeadDto> sheetHeadMap, ExportFileBaseService exportFileBaseService, FileExportApplyDetail fileExportApplyDetail)
    {
        this.fileExportApplyDetail = fileExportApplyDetail;
        this.exportFileBaseService = exportFileBaseService;
        this.minIoImageManager = CsApplicationContext.getBean(MinIoImageManager.class);

        String filePath = UUID.randomUUID().toString().replace("-","")+".xlsx";
        filePathList.add(filePath);
        exportExcelWriterBiz = new ExportExcelWriterBiz(sheetHeadMap,filePath);
    }

    public boolean writerData(TransferMessageDto sendMessage)
    {
        if (sendMessage.getConfig().getDealResult() == ExportDealResultTypeEnum.fail.code) {
            failMessages.append(",fail:").append(sendMessage.getConfig().getErrorMessage());
            return false;
        }

        if(sendMessage.getData()!=null && sendMessage.getData().length>0)
        {
            emptyDataTime = 0;
            // 保存Excel数据
            Pair<Integer,String> saveResult = writerData(sendMessage.getData(),sendMessage.getMessageData().getSheetName());
            if(StringUtils.isNotBlank(saveResult.getValue()))
            {
                failMessages.append(sendMessage.getConfig().getErrorMessage());
                return false;
            }
        }

        // 如果不是继续，那就是结束或者异常了
        if(sendMessage.getConfig().getDealResult() != ExportDealResultTypeEnum.continue_deal.code)
        {
            return false;
        }
        else
        {
            if(sendMessage.getData() == null || sendMessage.getData().length ==0)
            {
                emptyDataTime++;
                if(emptyDataTime>50)
                {
                    failMessages.append("程序连续").append(emptyDataTime).append("次返回空数据;");
                    return false;
                }
            }
        }
        return true;
    }

    public Set<String> getAllSheetName()
    {
        return exportExcelWriterBiz.getAllSheetName();
    }

    public Pair<Integer,String> writerData(byte[] data, String sheetName)
    {
        try {
            if(exportExcelWriterBiz.getSheetCount()>1)
            {
                if(exportExcelWriterBiz.hasMaxCount(sheetName))
                {
                    return Pair.of(totalRows,sheetName+"行数超过最大行数");
                }

                if(totalRows >= totalMaxCount)
                {
                    return Pair.of(totalRows,"excel总行数超过最大行数");
                }
            }
            else
            {
                if(exportExcelWriterBiz.hasMaxCount(sheetName))
                {
                    if(filePathList.size()>=10)
                    {
                        return Pair.of(totalRows,"最多只能导出10个文件");
                    }
                    String filePath = UUID.randomUUID().toString().replace("-","")+".xlsx";
                    filePathList.add(filePath);
                    exportExcelWriterBiz.newExcelWriter(filePath);
                }
            }

            int writerCount = exportExcelWriterBiz.writerData(sheetName, data);
            totalRows += writerCount;
            exportFileBaseService.updateStatus(fileExportApplyDetail.getId(),ExportStatusEnum.start_deal,totalRows, fileExportApplyDetail.getMessage());
            return Pair.of(totalRows,null);
        }
        catch (Exception ex)
        {
            log.error("写入数据异常",ex);
            return Pair.of(totalRows,ex.getMessage());
        }
    }

    public void updateFinishStatus()
    {
        updateFinishStatus(null);
    }

    public void updateFinishStatus(String errorMessage)
    {
        try {
            if(StringUtils.isNotBlank(errorMessage))
            {
                failMessages.append(errorMessage);
            }

            try {
                exportExcelWriterBiz.destroy();
            } catch (Exception ex) {
                log.warn("关闭writeSheet",ex);
            }

            // 修改导出状态为“表格制作中”
            exportFileBaseService.updateStatus(fileExportApplyDetail.getId(),ExportStatusEnum.save_excel,totalRows,null);

            // 上传文件
            uploadFiles();

            fileExportApplyDetail.setMessage(failMessages.toString());
            fileExportApplyDetail.setFileUrl(remoteFileNames);

            int statusCode = 0;
            if (!failMessages.isEmpty()) {
                statusCode = exportFileBaseService.updateStatus(fileExportApplyDetail.getId(),ExportStatusEnum.deal_exception,totalRows, fileExportApplyDetail.getMessage(),remoteFileNames);
            } else {
                statusCode = exportFileBaseService.updateStatus(fileExportApplyDetail.getId(),ExportStatusEnum.success,totalRows, fileExportApplyDetail.getMessage(),remoteFileNames);
            }

            if (statusCode<=0) {
                log.error("{} 结束状态更 {}", fileExportApplyDetail, statusCode);
            }
        }
        catch (Exception ex)
        {
            log.error("文件结束处理失败",ex);
        }
    }


    /**
     * 上传并判断是否成功，按成功与否分别写入不同变量等待更新数据库
     * @return boolean
     **/
    private void uploadFiles() {
        if (CollectionUtils.isEmpty(filePathList)) {
            // 没有文件，无需上传
            return ;
        }

        String modeCode = fileExportApplyDetail.getModeCode();
        String orgCode = fileExportApplyDetail.getOrgCode();

        if(StringUtils.isEmpty(modeCode))
        {
            modeCode = "other";
        }

        try {
            if(atomicInteger != null)
            {
                int intValue = atomicInteger.incrementAndGet();
                if(intValue>10)
                {
                    //TODO 进行加锁控制，用于限流
                    Thread.sleep(1000);
                }
            }

            for (String name : filePathList) {
                File file = new File(name);
                if(!file.exists())
                {
                    continue;
                }
                try {
                    String filePath = orgCode + "/" + modeCode + "/" +dateTimeFormatter.format(LocalDate.now()) + "/" +file.getName();
                    String tempMessages = minIoImageManager.saveFile(bucketName, name, filePath);

                    //TODO 上传失败异常记录
                    if (StringUtils.isNotBlank(tempMessages)) {
                        failMessages.append(tempMessages);
                    }

                    remoteFileNames.add(bucketName + "/" + filePath);
                }
                catch (Exception tempE)
                {
                    log.error("",tempE);
                    failMessages.append(tempE.getMessage());
                }
                finally {
                    file.delete();
                }
            }
        } catch (Exception e) {
            log.error("", e);
            failMessages.append("文件上传异常").append(e.getMessage());
        }
        finally {
            if(atomicInteger != null)
            {
                atomicInteger.addAndGet(-1);
            }
        }
    }

    @Override
    public void destroy() {
        try{
            if(exportExcelWriterBiz != null)
            {
                exportExcelWriterBiz.destroy();
            }
        }
        catch (Exception ex)
        {

        }
    }
}
